///////////////////////////////////////////////////////////////////////////////
//
// Licensed under the MIT License
//
// Copyright (c) 2010 Chris Colinsky
// All Rights Reserved
//
// version	0.5
// http://code.google.com/p/sugarcookie/
// http://code.google.com/p/sugarcookie/wiki/License
//
////////////////////////////////////////////////////////////////////////////////

package sugarcookie.text {
	import flash.accessibility.*;
	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.TextEvent;
	import flash.geom.Rectangle;
	import flash.geom.Transform;
	import flash.text.StyleSheet;
	import flash.text.TextField;
	import flash.text.TextFieldAutoSize;
	import flash.text.TextFormat;
	import flash.ui.ContextMenu;
	import flash.utils.describeType;
	
	import mx.logging.ILogger;
	import mx.logging.Log;
	import mx.utils.ObjectUtil;
	
	import sugarcookie.events.GenericEvent;
	import sugarcookie.style.StyleManager;
	import sugarcookie.utils.StringUtil;
	
	public class UIText extends Sprite {
		public static const INIT_TEXT_EVENT:String = "initTextEvent";
		public static const TOKENS:String = "tokens";
		public static const WINDOW_CHECK:String = "widowCheck";
		
		private var _log:ILogger;
		private var _tf:TextField;
		private var _props:Object;
		private var _id:String;
		private var _fp:Boolean = false;
		
		public function UIText(copy:String=null,props:Object=null,textField:TextField=null,commands:Array=null) {
			super();
			_log = Log.getLogger("sugarcookie.text.UIText");
			
			if (textField==null) {
				_tf = new TextField();
				_tf.autoSize = TextFieldAutoSize.LEFT;
			} else {
				_tf = TextField(addChild(textField));
				x = _tf.x;
				y = _tf.y;
				_tf.x = _tf.y = 0;
			}
			addChild(_tf);
			
			mouseChildren = false;
			
			_tf.mouseWheelEnabled = false;
			_tf.multiline = false;
			_tf.wordWrap = false;
			_tf.selectable = false;
			_tf.embedFonts = StyleManager.embed;
			
			if (props!=null) setProps(props);
			if (copy!=null) htmlText = copy;
			if (commands!=null) runCommands(commands);
		}
		
		public function clone():TextField {
			var clone:TextField = new TextField();
			var targetProps:XMLList = describeType(_tf).accessor;
			for (var i:int=0;i<targetProps.length();i++) {
				if (targetProps[i].@access=="readwrite" && (!(_tf[targetProps[i].@name] is TextFormat) || 
															!(_tf[targetProps[i].@name] is StyleSheet) || 
															!(_tf[targetProps[i].@name] is AccessibilityImplementation) ||
															!(_tf[targetProps[i].@name] is ContextMenu) ||
															!(_tf[targetProps[i].@name] is DisplayObject) ||
															!(_tf[targetProps[i].@name] is Rectangle) ||
															!(_tf[targetProps[i].@name] is Transform) ||
															!(_tf[targetProps[i].@name] is AccessibilityProperties)) ) {
					clone[targetProps[i].@name] = _tf[targetProps[i].@name];
				} 
			}
			clone.x = x;
			clone.y = y;
			return clone;
		}
		
		public function setStyleById(id:String):void {
			_tf.styleSheet = StyleManager.getStyleSheet(id);
		}
		
		public function get id():String {
			return _id;
		}
		
    	public function set id(value:String):void {
    		_id = value;
    	}
		
		public function get htmlText():String {
			return _tf.htmlText;
		}
		
    	public function set htmlText(str:String):void {
    		_tf.htmlText = unescape(str);
    	}
		
		public function textMethod(method:String,...args:Array):void {
			_tf[method].apply(null,args);
		}
    	
    	public function getTextProp(prop:String):Object {
    		var value:Object;
    		
    		try {
				value = _tf[prop];
			} catch (err:Error) {
				_log.error("Caught "+err.toString());
				return null;
			}
    		
			return value;
		}
		
		public function set textProps(obj:Object):void {
    		setProps(obj);
    	}
    	
    	public function set fancyPunctuation(value:Boolean):void {
    		_fp = value;
    		var _html:String = _tf.htmlText;
    		var regex:RegExp;
    		if (_fp) {
    			regex = /[a-zA-Z]'[a-zA-Z]/g;
    			_html = _html.replace(regex,makefancy);
    			function makefancy():String {
					var str:String = arguments[0];
					str = str.replace("'","’");
					return str;
				}
    		} else {
    			regex = /[a-zA-Z]’[a-zA-Z]/;
    			_html = _html.replace(regex,unfancy);
    			function unfancy():String {
					var str:String = arguments[0];
					str = str.replace("’","'");
					return str;
				}
    		}
    		_tf.htmlText = _html;
    	}
    	
    	public function get fancyPunctuation():Boolean {
    		return _fp;
    	}
		
		//command
		public function initTextEvent():void {
			mouseChildren = true;
			_tf.addEventListener(TextEvent.LINK,handleTextClick,false,0,true);
		}
		
		//command
		public function tokens():void {
			var regex:RegExp = /\(TM\)/;
			var newText:String = StringUtil.replaceAll(regex,_tf.htmlText,"<font face='GGSuperscript'>TM</font>");
			
			regex = /\(R\)/;
			newText = StringUtil.replaceAll(regex,newText,"<font face='GGSuperscript'>®</font>");
			
			regex = /\(C\)/;
			newText = StringUtil.replaceAll(regex,newText,"<font face='GGSuperscript'>©</font>");
			
			_tf.htmlText = newText;
		}
    	
		//command
    	public function widowCheck():void {
    		if (_tf.numLines<=1) return;
    		
    		var markerIndex:int = 0;
    		var newHTML:String = _tf.htmlText;
    		var widows:Array = [];
    		var paragraphs:Array = [];
    		var result:Object;
    		var i:int;
    		
    		for (i=0;i<_tf.numLines;i++) {
    			var lineText:String = _tf.getLineText(i);
    			result = StringUtil.wordCount(lineText);
    			
    			if (result.length==0) {
					paragraphs.push([markerIndex,i-1]);
					markerIndex = i+1;
    			} else if (result.length==1) {
    				widows.push(i);
    			}
    		}
    		paragraphs.push([markerIndex,_tf.numLines-1]);
    		
    		for (i=0;i<paragraphs.length;i++) {
    			for (var c:int=0;c<widows.length;c++) {
    				if (paragraphs[i][1]==widows[c]) {
    					var longestIndex:int = paragraphs[i][0];
    					for (var g:int=paragraphs[i][0]+1;g<=paragraphs[i][1];g++) {
    						if (_tf.getLineText(g).length>_tf.getLineText(longestIndex).length && g!=widows[c]) longestIndex=g;
    					}
    					
    					var editLine:String = _tf.getLineText(longestIndex);
    					result = StringUtil.wordCount(editLine);
    					
    					var newSnipit:String;
    					var oldSnipit:String = result.words[result.length-3]+" "+result.words[result.length-2]+" "+result.words[result.length-1];
    					if (String(result.words[result.length-1]).length>2 && (String(result.words[result.length-1]).length+String(result.words[result.length-2]).length>12) ) {
    						newSnipit = result.words[result.length-3]+" "+result.words[result.length-2]+"<br>"+result.words[result.length-1];
    					} else {
    						newSnipit = result.words[result.length-3]+"<br>"+result.words[result.length-2]+" "+result.words[result.length-1];
    					}
	    				newHTML = newHTML.replace(oldSnipit,newSnipit);
    					break;
    				}
    			}
    		}
    		
    		htmlText = newHTML;
    	}
    	
    	private function setProps(props:Object):void {
    		_props = props;
    		for (var i:String in _props) {
				try {
					_tf[i] = _props[i];
				} catch (err:Error) {
					_log.error("Caught "+err.toString());
				} 
			}
    	}
		
		private function runCommands(commands:Array):void {
			//TODO - how to enforce only real commands
			for (var i:int=0;i<commands.length;i++) this[commands[i]]();
		}
		
		private function handleTextClick(evt:TextEvent):void {
			dispatchEvent(new GenericEvent(evt.text,false,false,null,true));
		}
	}
}